<?php

/**
 * Obiekt sesji
 * 
 * Pozwala na zarządzanie danymi przy pomocy przestrzeni nazw, chroniąc je przez przypadkowym nadpisaniem przez różne komponenty.
 * Pozwala na stosowanie handlerów do przechowywania danych w sposób niekonwencjonalny.
 *
 */
class Rapide_Session
{
	private
		$_sSessionName,	
		$_sNameSpace;

	/**
	 * Utwórz sesję
	 * 
	 * Opcjonalny parametr służy do zarządzania sesją przy pomocy przestrzeni nazw.
	 * Dzięki niemu możliwe jest utworzenie wielu kontenerów na dane sesji bez obaw,
	 * że dojdzie do sytuacji, kiedy jeden kompontent nadpisze dane drugiego.
	 *
	 * @param string $sNameSpace
	 */
	public function __construct($sNameSpace = null)
	{
		$oConfig = new Rapide_Config;
		$oConfig->load('Session.php');

		/**
		 * Ustaw nazwę sesji
		 */

		$sSessionName = $oConfig->get('Session', 'session_name');

		$this->_sSessionName = $sSessionName ? $sSessionName : md5(_DIR);

		/**
		 * Ustaw przestrzeń nazw, jeżeli ją podano
		 */
		if(isset($sNameSpace))
		{
			$this->_sNameSpace = $sNameSpace;

			if(!isset($_SESSION[$this->_sNameSpace]))
				$_SESSION[$this->_sNameSpace] = array();
		}
	}

	/**
	 * Zwraca nazwę sesji
	 *
	 * @return string
	 */
	public function getSessionName()
	{
		return $this->_sSessionName;
	}

	/**
	 * Zwraca nazwę przestrzeni nazw
	 *
	 * @return string
	 */
	public function getNameSpaceName()
	{
		return $this->_sNameSpace;
	}

	/**
	 * Ustawia handler sesji
	 *
	 * @param Rapide_Session_Handler_Interface $oSessionHandler
	 */
	public function setHandler(Rapide_Session_Handler_Interface $oSessionHandler)
	{
		if($this->started())
		{
			$sError = 'Session has already started';
			throw new Rapide_Session_Exception($sError);
		}

		session_set_save_handler
		(
			array(& $oSessionHandler, 'open'),
			array(& $oSessionHandler, 'close'),
			array(& $oSessionHandler, 'read'),
			array(& $oSessionHandler, 'write'),
			array(& $oSessionHandler, 'destroy'),
			array(& $oSessionHandler, 'gc')
		);
	}

	/**
	 * Sprawdza, czy sesja już wystartowała
	 *
	 * @return bool
	 */
	public function started()
	{
		return (bool)strlen(session_id());
	}

	/**
	 * Startuje sesję
	 *
	 * @throws Rapide_Session_Exception jeżeli nagłówki zostały wcześniej przesłane
	 */
	public function start()
	{
		if(!$this->started())
		{
			if(headers_sent())
			{
				$sError = 'Headers already sent';
				throw new Rapide_Session_Exception($sError);
			}

			session_name($this->getSessionName());

			session_start();
		}
	}

	/**
	 * Zamyka sesję
	 * 
	 * Jeżeli sesja została utworzona przy pomocy przestrzeni nazw, zostanie jedynie wyczyszczona przestrzeń z danymi.
	 * W przypadku utworzenia generalnej sesji, cała sesja zostanie zniszczona.
	 *
	 * @throws Rapide_Session_Exception jeżeli sesja nie wystartowała
	 */
	public function close()
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		if(isset($this->_sNameSpace))
			$_SESSION[$this->_sNameSpace] = array();
		else
			$this->destroy();
	}

	/**
	 * Niszczy całą sesję
	 *
	 * @throws Rapide_Session_Exception jeżeli sesja nie wystartowała
	 */
	public function destroy()
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		session_destroy();
	}

	/**
	 * Zwraca wartość podanego parametru
	 * 
	 * Jeżeli parametr nie istnieje, zostaje zwrócowa wartość NULL
	 *
	 * @param string $sParameter
	 * @return mixed value
	 */
	public function __get($sParameter)
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		if(isset($this->_sNameSpace))
		{
			return isset($_SESSION[$this->_sNameSpace][$sParameter]) ?
						 $_SESSION[$this->_sNameSpace][$sParameter] :
						 null;
		}
		else
		{
			return isset($_SESSION[$sParameter]) ?
						 $_SESSION[$sParameter] :
						 null;
		}
	}

	/**
	 * Ustawa wartość parametru
	 *
	 * @param string $sParameter
	 * @param mixed $mValue
	 */
	public function __set($sParameter, $mValue)
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		if(isset($this->_sNameSpace))
			$_SESSION[$this->_sNameSpace][$sParameter] = $mValue;
		else
			$_SESSION[$sParameter] = $mValue;
	}

	/**
	 * Sprawdza, czy podany parametr istnieje
	 *
	 * @param string $sParameter
	 * @return bool
	 */
	public function __isset($sParameter)
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		if(isset($this->_sNameSpace))
			return isset($_SESSION[$this->_sNameSpace][$sParameter]);
		else
			return isset($_SESSION[$sParameter]);
	}

	/**
	 * Zwraca tablicę danych obecnej przestrzeni nazw
	 * 
	 * Jeżeli sesja nie została utworzona przy pomocy przestrzeni nazw,
	 * zostanie zwrócona tablica wszystkich danych sesji.
	 *
	 * @throws Rapide_Session_Exception jeżeli sesja nie wystartowała
	 * @return array
	 */
	public function getNameSpace()
	{
		if(!$this->started())
		{
			$sError = 'Session has not started yet';
			throw new Rapide_Session_Exception($sError);
		}

		if(isset($this->_sNameSpace))
			return $_SESSION[$this->_sNameSpace];
		else
			return $_SESSION;
	}
}

?>